﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CommandBase.h"
#include "GbmpUiPlatformCommandRegister.h"
#include "UiCommonDialog.h"
#include "Vector3d.h"
#include "GbmpUiPlatformCommandIds.h"
#include "IDocument.h"
#include "IModelView.h"
#include "IUserTransaction.h"


#include "IUiDocumentViewManager.h"
#include "QFamilyTreeWidgetUtil.h"
#include "IElementBasicInformation.h"
#include "IDrawingLayout.h"
#include "ModelViewDlg.h"
#include "IDrawingLayoutManager.h"
#include "QTreeWidgetPaper.h"
#include "CreateViewPortDlg.h"
#include "IPickPointAction.h"
#include "UiLayoutManager.h"
#include "IUiView.h"
#include "UiDocumentViewUtils.h"
#include "GcmpCommandState.h"
#include "IUiDocument.h"
#include "IGenericElement.h"
#include "IElementParameters.h"
#include "LayoutOrViewportParametersCustomizer.h"

#include "CommandParameters.h"
#include "IDrawingViewportType.h"
#include "UiViewUtils.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

CREATE_DEBUG_MODE(ViewportFrameInvisible, L"视口框默认不可见", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"启用此模式后，视口未激活时视口框预选或者选择时才可见。");
CREATE_DEBUG_MODE(IsEnableActiveViewport, L"鼠标双击视口，视口是否激活", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"鼠标双击视口，视口是否激活");
CREATE_DEBUG_MODE(IsSwitchActiveStateBetweenDifferentViewport, L"所属图纸上有其他激活的视口时，鼠标双击视口，是否使能激活状态", gcmp::DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20", L"前提条件是，图纸上需要有激活的视口");
CREATE_DEBUG_MODE(IsEnableViewportLODEffect, L"视口尺寸很小时，是否启动视口类LOD效果（开启后，不进行视口内容实时绘制）", gcmp::DebugModeGroup::DGMT_PERFORMANCE_TEST, L"GDMPLab", L"2023-12-20", L"适用于视口尺寸很小，用户基本无法看清楚视口内容的场景");
CREATE_DEBUG_MODE(IsDifferentBetweenOutsideAndInside, L"图纸的视口的外框与内框是否一致（设true,就是GAP所需要的内外框不一致；设false为一致，维持原视口行为）", gcmp::DebugModeGroup::DGMT_PERFORMANCE_TEST, L"GDMPLab", L"2023-12-20", L"图纸的视口的外框与内框是否一致（设true,就是GAP所需要的内外框不一致；设false为一致，维持原视口行为）");

class CreateViewportAction : public gcmp::ActionBase
{
public:
    CreateViewportAction(IDocument* pDocument, IModelView* pModelView, IDrawingLayout* pLayout, QTreeWidgetItem* pSelectedPaperItem,bool isMultiViewport, bool supportOverride);
    ~CreateViewportAction(void);
    virtual void InitAction(IUiView* pCurrentView) override;
    virtual void OnChildActionFinished(gcmp::IUiView* pCurrentView, const gcmp::ActionOutput& childActionReturnParam) override;


private:
    Coordinate3d GetUiViewCoord(const IModelView* pModelView)
    {
        ElementId idModelView = pModelView->GetElementId();
        Coordinate3d coordModelView;
        const IUiDocument* pUIDoc = UiDocumentViewUtils::GetCurrentUiDocument();
        DBG_WARN_AND_RETURN_UNLESS(pUIDoc != nullptr, coordModelView,L"pUIDoc为空",L"GDMPLab",L"2024-03-30");
        std::vector<const gcmp::IUiView*> vecUIViews = pUIDoc->GetAllUiViews();
        const IUiView* pUiViewFind = nullptr;
        FOR_EACH(pUIView, vecUIViews)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(pUIView != nullptr, L"pUIView为空",L"GDMPLab",L"2024-03-30");
            if (pUIView->GetModelViewId() == idModelView && !pUIView->IsSubUiView())
            {
                pUiViewFind = pUIView;
                break;
            }
        }
        if (pUiViewFind != nullptr)
        {
            return UiViewUtility::GetProjectionCoordinate(pUiViewFind);
        }
        else
        {
            return Coordinate3d(pModelView->GetOrigin(), pModelView->GetRightDirection(), pModelView->GetUpDirection());
        }
    }
private:
    std::vector<gcmp::Vector3d> m_pickedPoints;
    gcmp::Vector3d m_leftBottomPoint;
    bool m_isUserCancelled;

    IDocument* m_pDocument;
    IModelView* m_pModelView;
    IDrawingLayout* m_pLayout;
    QTreeWidgetItem* m_pSelectedPaperItem;
    bool m_isMultiViewport;
    bool m_supportOverride;
};

CreateViewportAction::CreateViewportAction(
    IDocument* pDocument, 
    IModelView* pModelView, 
    IDrawingLayout* pLayout, 
    QTreeWidgetItem* pSelectedPaperItem, 
    bool isMultiViewport,
    bool supportOverride)
    : m_pDocument(pDocument),
    m_pModelView(pModelView),
    m_pLayout(pLayout),
    m_pSelectedPaperItem(pSelectedPaperItem),
    m_isMultiViewport(isMultiViewport),
    m_supportOverride(supportOverride)
{
    SetCursorType(CursorType::CrossHairCursor);
}

CreateViewportAction::~CreateViewportAction()
{
    m_pDocument = nullptr;
    m_pModelView = nullptr;
    m_pLayout = nullptr;
    m_pSelectedPaperItem = nullptr;
}

void CreateViewportAction::InitAction(IUiView* pCurrentView)
{
    m_isUserCancelled = false;
    PickPointExchangeData exchangeDate(&m_leftBottomPoint, &m_isUserCancelled, &m_pickedPoints);
    gcmp::OwnerPtr<IPickPointAction> opPickPointAction = IPickPointAction::Create(exchangeDate, nullptr);
    StartChildAction(TransferOwnership(opPickPointAction));
}

void CreateViewportAction::OnChildActionFinished(gcmp::IUiView* pCurrentView, const gcmp::ActionOutput& childActionReturnParam)
{
    if (m_isUserCancelled)
    {
        CleanupTempGraphicsShape();
        MarkFinishStatus(ActionFinishStatus::Successful);
        UpdateView();
        return;
    }
    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(m_pDocument, GBMP_TR(L"创建图纸"), true);
    std::wstring errorMessage;

    if (!m_pLayout || !m_pModelView)
    {
        return;
    }

    IElementBasicInformation* pBasicInformation = m_pModelView->GetBasicInformation();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pBasicInformation, L"pBasicInformation为空",L"GDMPLab",L"2024-03-30");

    if (DEBUG_MODE(IsEnableViewportLODEffect))
        m_pLayout->SetIsEnableViewportLODEffect(true);
    else
        m_pLayout->SetIsEnableViewportLODEffect(false);
    
    IDrawingViewport* pViewPort;
    if (m_isMultiViewport)
    {
        Coordinate3d coordUiView = GetUiViewCoord(m_pModelView);
        pViewPort = m_pLayout->CreateMultiViewport(pBasicInformation->GetElementId(), m_pModelView->GetName(), coordUiView, m_leftBottomPoint, m_supportOverride);
    }
    else
    {
        if (DEBUG_MODE(IsDifferentBetweenOutsideAndInside))
        {
            pViewPort = m_pLayout->CreateViewport(pBasicInformation->GetElementId(), m_pModelView->GetName(), m_leftBottomPoint, &errorMessage, true);
        }
        else
        {
            pViewPort = m_pLayout->CreateViewport(pBasicInformation->GetElementId(), m_pModelView->GetName(), m_leftBottomPoint, &errorMessage, false);
        }
    }

    if (!pViewPort)
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"创建视口失败"), GBMP_TR(errorMessage), (int)(UiCommonDialog::ButtonType::OK));
        return;
    }
    
    if (DEBUG_MODE(IsEnableActiveViewport))
        pViewPort->SetIsEnableActive(false);
    else
        pViewPort->SetIsEnableActive(true);

    if (!m_isMultiViewport)
    {
        if (DEBUG_MODE(IsSwitchActiveStateBetweenDifferentViewport))
            pViewPort->SetIsSwitchActiveState(true);
        else
            pViewPort->SetIsSwitchActiveState(false);
    }

    if (DEBUG_MODE(ViewportFrameInvisible))
    {
        pViewPort->SetFrameVisibility(GraphicsNodeVisibility::HighlightedExactly_Or_SelectedExactly);
    }
    else
    {
        pViewPort->SetFrameVisibility(GraphicsNodeVisibility::Always);
    }


    IGenericElement* pGenericElement = quick_cast<IGenericElement>(pViewPort->GetOwnerElement());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElement, L"转换失败",L"GDMPLab",L"2024-03-30");
    IElementParameters* pElementParameters = pGenericElement->GetElementParameters();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementParameters, L"pElementParameters为空",L"GDMPLab",L"2024-03-30");
    pElementParameters->SetElementParametersCustomizer(NEW_AS_OWNER_PTR(ViewPortParametersCustomizer, pGenericElement));
    pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ViewportScaleOverride));
    pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ViewportCropByBorderOverride));
    pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ViewportBorderVisibleOverride));

    // 为视口添加类型
    IDrawingViewportType* pViewportType = IDrawingViewportType::Create(m_pDocument, pViewPort->GetName());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pViewportType, L"pViewportType为开",L"GDMPLab",L"2024-03-30");
    IElementBasicInformation* pViewportTypeBasicInformation = pViewportType->GetBasicInformation();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pViewportTypeBasicInformation, L"pViewportTypeBasicInformation为空",L"GDMPLab",L"2024-03-30");
    pViewportTypeBasicInformation->SetName(pViewPort->GetName());
    IElementParameters* pViewportTypeParameters = pViewportType->GetElementParameters();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pViewportTypeParameters, L"pViewportTypeParameters为空",L"GDMPLab",L"2024-03-30");
    pViewportTypeParameters->SetElementParametersCustomizer(NEW_AS_OWNER_PTR(DrawingViewportTypeParametersCustomizer, pViewportType));
    IElementBasicInformation* pGenericElementBasicInformation = pGenericElement->GetBasicInformation();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElementBasicInformation, L"pGenericElementBasicInformation为空",L"GDMPLab",L"2024-03-30");
    pGenericElementBasicInformation->SetTypeId(pViewportType->GetElementId());

    if (opTransaction)
    {
        opTransaction->Commit();
    }

    if (QTreeWidgetPaper::FindChildWidgetItem(pViewPort->GetName()) == nullptr)
    {
        QTreeWidgetPaper::UpdateViewPortItem(m_pSelectedPaperItem, pViewPort);
    }
    CleanupTempGraphicsShape();
    UpdateView();
    MarkFinishStatus(ActionFinishStatus::Successful);
}



const std::wstring& ParamKey_IsMultiViewport = L"IsMultiViewport";
//创建视口
class CmdCreateViewPort : public CommandBase
{
public:
    CmdCreateViewPort();
    CmdCreateViewPort(const std::wstring& strCommandId);
    ~CmdCreateViewPort();

public:
    // Command接口实现
    virtual gcmp::OwnerPtr<gcmp::IAction> ExecuteCommand(const gcmp::CommandParameters& cmdParams) override;
    virtual bool IsEnabled() const override;
    virtual bool IsVisible() const override;
public:
    IDrawingLayout* GetSelectedLayout(QTreeWidgetItem* pSelectedPaperItem);
private:
    QTreeWidgetItem* m_pSelectedPaperItem;
};



CmdCreateViewPort::CmdCreateViewPort() : CommandBase(ID_CMD_CREATE_VIEW_PORT) 
{
}
CmdCreateViewPort::CmdCreateViewPort(const std::wstring& strCommandId) : CommandBase(strCommandId)
{

}
CmdCreateViewPort::~CmdCreateViewPort()
{
    m_pSelectedPaperItem = nullptr;
}

gcmp::OwnerPtr<IAction> CmdCreateViewPort::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IUiDocumentViewManager* pUiDocViewManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocViewManager, L"pUiDocViewManager为空",L"GDMPLab",L"2024-03-30");

    IUiDocument* pUiDoc = pUiDocViewManager->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDoc, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");

    bool IsMultiViewport = false;
    auto iter = cmdParams.find(ParamKey_IsMultiViewport);
    if (iter != cmdParams.end())
    {
        IsMultiViewport = iter->second.AsBool();
    }
    bool supportOverride = false;
    auto& item = cmdParams.find(L"SupportOverride");
    if (item != cmdParams.end())
        supportOverride = item->second.AsBool();

    CreateViewPortDlg dlg;
    dlg.UpdateModelViewsTree(pUiDoc,IsMultiViewport);

    if (QDialog::Accepted == dlg.exec())
    {
        QTreeWidgetItem* pSelectedItem = dlg.GetSelectedItem();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pSelectedItem, L"pSelectedItem为空",L"GDMPLab",L"2024-03-30");
        Int64 viewId = pSelectedItem->data(0, MODEL_VIEW_USER_DATA_ROLE).toLongLong();
        if (!viewId)
        {
            return nullptr;
        }
        std::vector<IModelView *> modelViews = IModelView::GetAllModelViews(pDoc);
        IModelView* pModelView = nullptr;
        for (int i = 0; i < modelViews.size(); ++i)
        {
            pModelView = modelViews[i];
            if (!pModelView)
            {
                continue;
            }
            IElementBasicInformation* pElementBasicInformation = pModelView->GetBasicInformation();
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementBasicInformation, L"pElementBasicInformation为空",L"GDMPLab",L"2024-03-30");
            Int64 curviewId = pElementBasicInformation->GetElementId().AsInt64();
            if (viewId == curviewId)
            {
                break;
            }
        }
        //double leftOffset, rightOffset, topOffset, downOffset;

        IUiView* pCurrentView = pUiDocViewManager->GetCurrentUiView();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurrentView, L"pCurrentView is nullptr",L"GDMPLab",L"2024-03-30");
        IModelView* pLayoutModelView = pCurrentView->GetModelView();            
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLayoutModelView, L"pLayoutModelView is nullptr",L"GDMPLab",L"2024-03-30");
        std::wstring errorMessage;
        IDrawingLayoutManager* pLayoutManager = IDrawingLayoutManager::Get(pDoc, &errorMessage);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLayoutManager, L"获取图纸管理器失败",L"GDMPLab",L"2024-03-30");
        IDrawingLayout* pCurLayout = pLayoutManager->GetLayout(pLayoutModelView->GetName());
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCurLayout, L"pLayout is nullptr",L"GDMPLab",L"2024-03-30");

        QTreeWidgetItem* pCurItem = QTreeWidgetPaper::FindChildWidgetItem(pCurLayout->GetName());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCurItem, L"pCurItem为空",L"GDMPLab",L"2024-03-30");
        m_pSelectedPaperItem = pCurItem;

        return NEW_AS_OWNER_PTR(CreateViewportAction, pDoc, pModelView, pCurLayout, m_pSelectedPaperItem,IsMultiViewport, supportOverride);

    }
    return nullptr;
}

bool CmdCreateViewPort::IsEnabled() const
{
    IUiDocumentViewManager* pUiDocumentViewManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiDocumentViewManager, L"pUiDocumentViewManager不能为空",L"GDMPLab",L"2024-03-30");
    IUiDocument* pUiDocument = pUiDocumentViewManager->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiDocument, L"pUiDocument为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDocument->GetDbDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc不能为空",L"GDMPLab",L"2024-03-30");
    IUiView* pCurrentView = pUiDocumentViewManager->GetCurrentUiView();
    if (nullptr != pCurrentView)
    {
        IModelView* pModelView = pCurrentView->GetModelView();
        if (nullptr != pModelView)
        {
            const BuiltInViewType mvIndex = pModelView->GetViewType();
            if (mvIndex == BuiltInViewType::Drawing)
            {
                std::wstring errorMessage;
                IDrawingLayoutManager* pLayoutManager = IDrawingLayoutManager::Get(pDoc, &errorMessage);
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pLayoutManager, L"获取图纸管理器失败",L"GDMPLab",L"2024-03-30");
                IDrawingLayout* pLayout = pLayoutManager->GetLayout(pModelView->GetName());
                if (pLayout)
                {
                    IDrawingViewport* pActivatedViewport = pLayout->GetActiveViewport();
                    if (pActivatedViewport)
                    {
                        return false;
                    }
                }
                return true;
            }
        }
    }
    return false;
}

bool CmdCreateViewPort::IsVisible() const
{
    return gcmp::GcmpCommandState::IsInProjectEnvironment() && !gcmp::GcmpCommandState::IsInAnimationEnvironment();
}

IDrawingLayout* CmdCreateViewPort::GetSelectedLayout(QTreeWidgetItem* pSelectedPaperItem)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pSelectedPaperItem, L"pSelectedPaperItem为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    std::wstring errorMessage = L"";
    IDrawingLayoutManager* pLayoutsManager = IDrawingLayoutManager::Get(pDoc, &errorMessage);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pLayoutsManager, L"pLayoutsManager为空",L"GDMPLab",L"2024-03-30");
    IDrawingLayout* pSelectedLayout = pLayoutsManager->GetLayout(pSelectedPaperItem->text(0).toStdWString());
    if (pSelectedLayout)
    {
        return pSelectedLayout;
    }
    else
    {
        return nullptr;
    }
}

REGISTER_GM_COMMAND(CmdCreateViewPort)


//创建视口
class CmdCreateMultiViewPort : public CmdCreateViewPort 
{
public:
    CmdCreateMultiViewPort();
    CmdCreateMultiViewPort(const std::wstring& commandId);
    virtual ~CmdCreateMultiViewPort();

public:
    // Command接口实现
    virtual gcmp::OwnerPtr<gcmp::IAction> ExecuteCommand(const gcmp::CommandParameters& cmdParams) override;

public:
    //IDrawingLayout* GetSelectedLayout(QTreeWidgetItem* pSelectedPaperItem);
private:
    QTreeWidgetItem* m_pSelectedPaperItem;
};

CmdCreateMultiViewPort::CmdCreateMultiViewPort() : CmdCreateViewPort(ID_CMD_CREATE_VIEW_PORT_MULTI)
{
}

CmdCreateMultiViewPort::CmdCreateMultiViewPort(const std::wstring& commandId) 
    : CmdCreateViewPort(commandId)
{
}

CmdCreateMultiViewPort::~CmdCreateMultiViewPort()
{
   
}
gcmp::OwnerPtr<IAction> CmdCreateMultiViewPort::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    gcmp::CommandParameters commandParemeters = cmdParams;
    commandParemeters.insert(std::make_pair(ParamKey_IsMultiViewport, CommandParameterValue(true)));

    return CmdCreateViewPort::ExecuteCommand(commandParemeters);
}

REGISTER_GM_COMMAND(CmdCreateMultiViewPort)
//////////////////////////////////////////////////////////////////////////////////////////////
class CmdCreateMultiViewPortOverride : public CmdCreateMultiViewPort
{
public:
    CmdCreateMultiViewPortOverride();
    ~CmdCreateMultiViewPortOverride() {}

    virtual gcmp::OwnerPtr<gcmp::IAction> ExecuteCommand(const gcmp::CommandParameters& cmdParams) override;
};

CmdCreateMultiViewPortOverride::CmdCreateMultiViewPortOverride()
    : CmdCreateMultiViewPort(ID_CMD_CREATE_VIEW_PORT_MULTI_OVERRIDE)
{

}

gcmp::OwnerPtr<gcmp::IAction> CmdCreateMultiViewPortOverride::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    gcmp::CommandParameters commandParemeters = cmdParams;
    commandParemeters.insert(std::make_pair(L"SupportOverride", CommandParameterValue(true)));

    return CmdCreateMultiViewPort::ExecuteCommand(commandParemeters);
}

REGISTER_GM_COMMAND(CmdCreateMultiViewPortOverride)
